package com.gitee.wsl.ext.string

// [ \f\n\r\t\v]
fun String.stripAllSpace() = replace("\\s+".toRegex(), "")

fun String.letters() = replace("[^a-zA-Z]".toRegex(), "")

fun String.specialTrim(): String = this.trim { it <= ' ' }.replace(" +".toRegex(), String.SPACE_SEPARATOR)

fun String.escapeTurtleString(): String {
    return replace("\\", "\\\\").replace("\"", "\\\"")
}

fun String.substringUseLength(start: Int, length: Int = this.length): String {
    val low = (if (start >= 0) start else this.length + start).coerceIn(0, this.length)
    val high = (if (length >= 0) low + length else this.length + length).coerceIn(0, this.length)
    return if (high < low) "" else this.substring(low, high)
}

//fun String.toCharArray() = CharArray(length) { this@toCharArray[it] }

fun String.withoutRange(range: IntRange): String = this.substringUseLength(0, range.first) + this.substringUseLength(range.last + 1)

fun String.withoutIndex(index: Int): String = this.substringUseLength(0, index) + this.substringUseLength(index + 1)

fun String.withInsertion(index: Int, insertedText: String): String {
    val before = this.substringUseLength(0, index)
    val after = this.substringUseLength(index, this.length)
    return "$before$insertedText$after"
}

/**
 * According to the TOML standard (https://toml.io/en/v1.0.0#string) single quote is prohibited.
 * But in ktoml we don't see any reason why we cannot escape it. Anyway, by the TOML specification we should fail, so
 * why not to try to handle this situation at least somehow.
 *
 * Conversion is done after we have trimmed technical quotes and won't break cases when the user simply used a backslash
 * as the last symbol (single quote) will be removed.
 */
fun String.convertSingleQuotes(): String = this.replace("\\'", "'")

/**
 *  When the last non-whitespace character on a line is an unescaped \, it will
 *  be trimmed along with all whitespace (including newlines) up to the next
 *  non-whitespace character or closing delimiter.
 *
 * @return string with the result
 */
fun String.convertLineEndingBackslash(): String {
    // We shouldn't trim if the size of the split array == 1
    // It means there is no ending backslash, and we should keep all spaces
    val splitEndingBackslash = this.split("\\\n")
    return if (splitEndingBackslash.size == 1) {
        this
    } else {
        splitEndingBackslash.joinToString("") { it.trimStart() }
    }
}

/**
 * @return a sliced copy of this string from start to the last occurrence of [string] if it exists,
 *         this string otherwise
 */
fun String.takeUntilLastOccurrence(string: String): String {
    // Trim trailing #s preceeded by a space
    val trailingIndex = lastIndexOf(string)
    return if (trailingIndex >= 0) {
        substring(0, trailingIndex)
    } else {
        this
    }
}


/**
 * Trims this string to a max length of [maxLength]. Returns original String if it's length < [maxLength].
 */
fun String.ofMaxLength(maxLength: Int): String {
    if(this.length > maxLength && maxLength > 0) {
        return this.substring(0, maxLength)
    }

    return this
}


fun String.substringAfterOrNull(delimiter: Char): String? = if (this.contains(delimiter)) this.substringAfter(delimiter) else null
fun String.substringBeforeOrNull(delimiter: Char): String? = if (this.contains(delimiter)) this.substringBefore(delimiter) else null
fun String.substringAfterLastOrNull(delimiter: Char): String? = if (this.contains(delimiter)) this.substringAfterLast(delimiter) else null
fun String.substringBeforeLastOrNull(delimiter: Char): String? = if (this.contains(delimiter)) this.substringBeforeLast(delimiter) else null

fun String.substringAfterOrNull(delimiter: String): String? = if (this.contains(delimiter)) this.substringAfter(delimiter) else null
fun String.substringBeforeOrNull(delimiter: String): String? = if (this.contains(delimiter)) this.substringBefore(delimiter) else null
fun String.substringAfterLastOrNull(delimiter: String): String? = if (this.contains(delimiter)) this.substringAfterLast(delimiter) else null
fun String.substringBeforeLastOrNull(delimiter: String): String? = if (this.contains(delimiter)) this.substringBeforeLast(delimiter) else null
